package com.jacky.ws.handler;

import com.corundumstudio.socketio.AckRequest;
import com.corundumstudio.socketio.SocketIOClient;
import com.corundumstudio.socketio.SocketIONamespace;
import com.corundumstudio.socketio.SocketIOServer;
import com.corundumstudio.socketio.annotation.OnConnect;
import com.corundumstudio.socketio.annotation.OnDisconnect;
import com.corundumstudio.socketio.annotation.OnEvent;
import com.jacky.ws.cache.ClientCache;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;

@Component
public class SocketEventHandler {

    private final static Logger LOG = LoggerFactory.getLogger(SocketEventHandler.class);

    private final ClientCache clientCache;

    public SocketEventHandler(ClientCache clientCache) {
        this.clientCache = clientCache;
    }

    /**
     * 客户端建立连接
     *
     * @param client 客户端的SocketIO
     */
    @OnConnect
    public void onConnect(SocketIOClient client) {
        // todo 这里还可以对不同的namespace进行区分
        String userId = client.getHandshakeData().getSingleUrlParam("userId");
        SocketIONamespace namespace = client.getNamespace();
        // 同一个页面sessionId是一样的
        UUID sessionId = client.getSessionId();
        LOG.info("namespace:{},userId:{},sessionId:{} 建立连接", namespace.getName(), userId, sessionId);
        clientCache.cacheClient(userId, sessionId, client);
    }

    /**
     * 客户端断开连接
     *
     * @param client 客户端的SocketIO
     */
    @OnDisconnect
    public void onDisconnect(SocketIOClient client) {
        UUID sessionId = client.getSessionId();
        String userId = client.getHandshakeData().getSingleUrlParam("userId");
        SocketIONamespace namespace = client.getNamespace();
        // 这里只会删除用户某个页面的会话缓存,不会删除该用户不同会话的缓存;
        // 比如 用户同时在edge和google浏览器建立了连接,userId相同,但是sessionId是不同的,当google浏览器的连接断开时
        // 只会删除这个用户ID下 sessionId为google建立时的缓存,另一个不会
        clientCache.removeClientByUserId(userId, sessionId);
        LOG.info("namespace:{},userId:{},sessionId:{} 断开连接", namespace.getName(), userId, sessionId);
    }

    @OnEvent("getUserRooms")
    public void getUserRooms(SocketIOClient client, String data, AckRequest ackRequest) {
        String user = client.getHandshakeData().getSingleUrlParam("userId");
        Set<String> allRooms = client.getAllRooms();
        allRooms.forEach(room -> LOG.info("用户:{},房间名:{}", user, room));

        if (ackRequest.isAckRequested()) {
            ackRequest.sendAckData(List.of(allRooms));
        }
    }

    @OnEvent("joinRoom")
    public void joinRooms(SocketIOClient client, String data, AckRequest ackRequest) {
        client.joinRoom(data);
        if (ackRequest.isAckRequested()) {
            ackRequest.sendAckData("加入房间", "成功");
        }
    }

    @OnEvent("leaveRoom")
    public void leaveRooms(SocketIOClient client, String data, AckRequest ackRequest) {
        client.leaveRoom(data);
        if (ackRequest.isAckRequested()) {
            ackRequest.sendAckData("离开房间", "成功");
        }
    }

    @OnEvent("sendRoomMessage")
    public void sendRoomMessage(SocketIOClient client, String data, AckRequest ackRequest) {
        String userId = client.getHandshakeData().getSingleUrlParam("userId");
        Set<String> allRooms = client.getAllRooms();
        allRooms.forEach(room -> {
            LOG.info("房间:{}", room);
            // 发送给指定命名空间以及房间的人,并且排队自己
//            server.getNamespace("/socketIo").getRoomOperations(room).sendEvent("message", client, data);

            // 发送给指定命名空间以及房间的人,并且包括自己
//            server.getNamespace("/socketIo").getRoomOperations(room).sendEvent("message", data);
        });
        if (ackRequest.isAckRequested()) {
            ackRequest.sendAckData("发送消息到指定房间成功", "成功");
        }
    }

    @OnEvent("sendNamespaceMessage")
    public void sendNamespaceMessage(SocketIOClient client, String data, AckRequest ackRequest) {
        String userId = client.getHandshakeData().getSingleUrlParam("userId");
        Set<String> allRooms = client.getAllRooms();
        allRooms.forEach(room -> {
            LOG.info("房间:{}", room);
            // 发送给指定命名空间以及房间的人,并且排队自己
//            server.getNamespace("/socketIo").getRoomOperations(room).sendEvent("message", client, data);
        });
        if (ackRequest.isAckRequested()) {
            ackRequest.sendAckData("发送消息到指定房间成功", "成功");
        }
    }

    @OnEvent("sendP2PMessage")
    public void sendP2PMessage(SocketIOClient client, String data, AckRequest ackRequest) {
        String userId = client.getHandshakeData().getSingleUrlParam("userId");
        Map<UUID, SocketIOClient> clientMap = clientCache.userClients(userId);
        for (UUID uuid : clientMap.keySet()) {
//            server.getNamespace("/socketIo").getClient(uuid).sendEvent("message", data);
        }
        if (ackRequest.isAckRequested()) {
            ackRequest.sendAckData("发送消息到指定房间成功", "成功");
        }
    }

}
